home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1992-1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- //////////////////////////////////////////////////////////////////////
- // Stretch.c++ - implementation of the stretch abstract class
- //
- // A road is made up of stretches of road. Each stretch
- // is of some type - straightaway, curve, loop, etc.
- //
- // This is the abstract base class from which all types
- // of stretches are derived.
- //////////////////////////////////////////////////////////////////////
-
- #include "Stretch.h"
- #include "Render.h"
- #include "Car.h"
- #include "Dynamics.h"
- #include "MiscMath.h"
- #include "Scenery.h"
-
- int Stretch::_ahead = 2; // number of stretches to draw ahead of this one
- int Stretch::_drawn = 0; // number of stretches drawn in current rendering
-
-
- Stretch::Stretch(Stretch *prev, Stretch *next)
- {
-
- _prev = prev;
- _next = next;
-
- if (_prev)
- {
- if (_prev->get_next())
- fprintf(stderr,"Previous stretch already has a next\n");
-
- _prev->set_next(this);
- }
-
- if (_next)
- {
- if (_next->get_prev())
- fprintf(stderr,"Next stretch already has a previous\n");
-
- _next->set_prev(this);
- }
-
- // list of cars currently on this stretch
- _car_list = new SbPList();
- }
-
-
- // modify step size to exactly match length/segment_count
- void Stretch::compute_step()
- {
- _num_markers = (int)(_length/_step) + 1;
- _step = _length/(float)(_num_markers - 1);
- }
-
-
- void Stretch::allocate_data()
- {
- _data = new StretchData[_num_markers];
- _median_data = new StretchData[_num_markers];
- _left_terrain_data = new StretchData[_num_markers];
- _right_terrain_data = new StretchData[_num_markers];
- }
-
-
- Stretch::~Stretch()
- {
- // delete [_num_markers] _data;
- // delete [_num_markers] _median_data;
- // delete [_num_markers] _left_terrain_data;
- // delete [_num_markers] _right_terrain_data;
- delete [] _data;
- delete [] _median_data;
- delete [] _left_terrain_data;
- delete [] _right_terrain_data;
- }
-
-
- // rotate the data and normals about the center of
- // the road by bank radians counter clockwise
- void Stretch::rotate_bank(int i, float bank)
- {
- // axis to rotate about
- SbVec3f horizontal = _data[i].right - _data[i].left;
- SbVec3f axis = horizontal.cross(_data[i].normal);
- axis.normalize();
-
- SbRotation bank_quat(axis,bank);
- SbMatrix xform, trans_back, rot_bank;
-
- SbVec3f temp;
-
- // transform the left and right data points by translating
- // them back to the origin (by middle data), rotating by bank,
- // then translating back
- xform.identity();
-
- xform.setTranslate(_data[i].middle);
-
- rot_bank.setRotate(bank_quat);
- xform = xform.multLeft(rot_bank);
-
- trans_back.setTranslate(- _data[i].middle);
- xform = xform.multLeft(trans_back);
-
-
- // transform the points
- temp = _data[i].left;
- xform.multVecMatrix(temp,_data[i].left);
-
- temp = _data[i].right;
- xform.multVecMatrix(temp,_data[i].right);
-
- // the normal only gets rotated
- SbMatrix bank_mat;
- bank_mat.setRotate(bank_quat);
- temp = _data[i].normal;
- bank_mat.multDirMatrix(temp,_data[i].normal);
- }
-
-
- void Stretch::find_previous(SbVec3f &prev_offset, SbRotation &prev_orientation)
- {
- if (_prev)
- {
- prev_offset = _prev->get_offset();
- prev_orientation = _prev->get_orientation();
- }
- else
- {
- SbVec3f up(0.0,1.0,0.0);
- prev_offset.setValue(0.0,0.0,0.0);
- prev_orientation.setValue(up,0.0);
- }
- }
-
-
- // match up ends
- void Stretch::match_ends()
- {
-
- if (_prev)
- {
- _data[0].left = _prev->get_left(_prev->get_count() - 1);
- _data[0].middle = _prev->get_middle(_prev->get_count() - 1);
- _data[0].right = _prev->get_right(_prev->get_count() - 1);
- _data[0].normal = _prev->get_normal(_prev->get_count() - 1);
-
- _median_data[0].left = _prev->get_left_median(_prev->get_count() - 1);
- _median_data[0].right = _prev->get_right_median(_prev->get_count()- 1);
-
- _left_terrain_data[0].left =
- _prev->get_left_terrain(_prev->get_count()- 1).left;
- _left_terrain_data[0].right =
- _prev->get_left_terrain(_prev->get_count()-1).right;
-
- _right_terrain_data[0].left =
- _prev->get_right_terrain(_prev->get_count()- 1).left;
- _right_terrain_data[0].right =
- _prev->get_right_terrain(_prev->get_count()-1).right;
- }
-
- if (_next)
- {
- _data[_num_markers - 1].left = _next->get_left(0);
- _data[_num_markers - 1].middle = _next->get_middle(0);
- _data[_num_markers - 1].right = _next->get_right(0);
- _data[_num_markers - 1].normal = _next->get_normal(0);
-
- _median_data[_num_markers - 1].left = _next->get_left_median(0);
- _median_data[_num_markers - 1].right = _next->get_right_median(0);
-
- _left_terrain_data[_num_markers - 1].left =
- _next->get_left_terrain(0).left;
- _left_terrain_data[_num_markers - 1].right =
- _next->get_left_terrain(0).right;
-
- _right_terrain_data[_num_markers - 1].left =
- _next->get_right_terrain(0).left;
- _right_terrain_data[_num_markers - 1].right =
- _next->get_right_terrain(0).right;
- }
- }
-
-
- void Stretch::transform_data(SbVec3f prev_offset, SbRotation prev_orientation)
- {
- // Rotate the data and normals by accumulated rotation
- SbMatrix rot_mat;
- prev_orientation.getValue(rot_mat);
-
- // transform the data
- for (int j = 0; j < _num_markers; j++)
- {
- SbVec3f rot_left, rot_middle, rot_right;
- SbVec3f rot_norm;
-
- // rotate the left and right data
- rot_mat.multDirMatrix(_data[j].left, rot_left);
- rot_mat.multDirMatrix(_data[j].middle, rot_middle);
- rot_mat.multDirMatrix(_data[j].right, rot_right);
-
- // translate the left and right data
- _data[j].left = rot_left + prev_offset;
- _data[j].middle = rot_middle + prev_offset;
- _data[j].right = rot_right + prev_offset;
-
- // median
- _median_data[j].left =
- _data[j].left + (1.0-STRIPE_WIDTH)*(_data[j].middle - _data[j].left);
-
- _median_data[j].right =
- _data[j].middle + STRIPE_WIDTH*(_data[j].right - _data[j].middle);
-
- // terrain
- _left_terrain_data[j].left =
- _data[j].left + TERRAIN_WIDTH*(_data[j].left - _data[j].middle);
- _left_terrain_data[j].right = _data[j].left;
-
- _right_terrain_data[j].right =
- _data[j].middle + TERRAIN_WIDTH*(_data[j].right - _data[j].middle);
- _right_terrain_data[j].left = _data[j].right;
-
- // rotate, but do not translate, the normals
- rot_mat.multDirMatrix(_data[j].normal, rot_norm);
-
- _data[j].normal = rot_norm;
-
- _median_data[j].left += STRIPE_HEIGHT*_data[j].normal;
- _median_data[j].right += STRIPE_HEIGHT*_data[j].normal;
- }
-
- // offset from origin to end of this stretch
- _offset = _data[_num_markers-1].middle;
- }
-
- // This is ugly. This is awful. This is disgusting.
- // But it only took 2 minutes to hack together.
- void Stretch::init_scenery()
- {
- int i;
- SbVec3f vec;
-
- vec = (_data[0].left - _data[0].middle);
- vec.normalize();
- vec *= SCENERY_OFFSET;
- _pole_pos = _data[0].left + vec;
-
- i = _num_markers/3;
- vec = (_data[i].right - _data[i].middle);
- vec.normalize();
- vec *= SCENERY_OFFSET;
- _tree1_pos = _data[i].right + vec;
-
- i = 2*_num_markers/3;
- vec = (_data[i].left - _data[i].middle);
- vec.normalize();
- vec *= SCENERY_OFFSET;
- _tree2_pos = _data[i].left + vec;
- }
-
-
- // Things are rendered back to front so we don't have to use
- // the zbuffer
- void Stretch::draw(
- int start_marker, int display_mode, Car * ignore_car) const
- {
- if (_next && (_drawn++ < _ahead))
- _next->draw(0, display_mode, ignore_car);
-
- _drawn--;
-
- Boolean last_backface = getbackface();
- backface(TRUE);
-
- if (_type == CURVE)
- {
- draw_asphalt(start_marker, display_mode);
- draw_stripes(start_marker, display_mode);
- draw_terrain(start_marker, display_mode);
- draw_scenery(display_mode);
- draw_cars(ignore_car, display_mode);
- }
- else if ((_type == STRAIGHT) || (_type == CONNECT))
- {
- if (_hill_angle < 0.0) // hills that curve down
- {
- draw_terrain(start_marker, display_mode);
- draw_scenery(display_mode);
- draw_asphalt(start_marker, display_mode);
- draw_stripes(start_marker, display_mode);
- draw_cars(ignore_car, display_mode);
- }
- else // flats and hills that curve up
- {
- draw_asphalt(start_marker, display_mode);
- draw_stripes(start_marker, display_mode);
- draw_terrain(start_marker, display_mode);
- draw_scenery(display_mode);
- draw_cars(ignore_car, display_mode);
- }
- }
- else if (_type == LOOP)
- {
- draw_cars(ignore_car, display_mode);
- draw_asphalt(start_marker, display_mode);
- draw_stripes(start_marker, display_mode);
- }
-
- backface(last_backface);
- }
-
-
-
- void Stretch::draw_scenery(int display_mode) const
- {
- // draw back to front
-
- // draw_trees
- pushmatrix();
- translate(_tree2_pos[0],_tree2_pos[1],_tree2_pos[2]);
- draw_tree(display_mode);
- popmatrix();
-
- pushmatrix();
- translate(_tree1_pos[0],_tree1_pos[1],_tree1_pos[2]);
- draw_tree(display_mode);
- popmatrix();
-
- // draw telephone pole
- pushmatrix();
- translate(_pole_pos[0],_pole_pos[1],_pole_pos[2]);
- draw_pole(display_mode);
- popmatrix();
- }
-
-
- void Stretch::draw_terrain(int start_marker, int display_mode) const
- {
- if (display_mode == RENDER_WIREFRAME)
- return; // no terrain if in wireframe mode
-
- int i;
-
- // draw terrain
- cpack(GRASS_COL);
-
- if ((_type == STRAIGHT) && (_hill_angle == 0.0))
- {
- bgnpolygon();
- v3f((float *)_left_terrain_data[0].left.getValue());
- v3f((float *)_left_terrain_data[0].right.getValue());
- v3f((float *)_left_terrain_data[_num_markers-1].right.getValue());
- v3f((float *)_left_terrain_data[_num_markers-1].left.getValue());
- endpolygon();
-
- bgnpolygon();
- v3f((float *)_right_terrain_data[0].left.getValue());
- v3f((float *)_right_terrain_data[0].right.getValue());
- v3f((float *)_right_terrain_data[_num_markers-1].right.getValue());
- v3f((float *)_right_terrain_data[_num_markers-1].left.getValue());
- endpolygon();
- }
- else
- {
- int step = 2*_drawn;
- if (!step) step++;
-
- // on left side of road
- bgnqstrip();
- for (i = _num_markers-1; i > start_marker; i -= step)
- {
- v3f((float *)_left_terrain_data[i].right.getValue());
- v3f((float *)_left_terrain_data[i].left.getValue());
- }
- v3f((float *)_left_terrain_data[start_marker].right.getValue());
- v3f((float *)_left_terrain_data[start_marker].left.getValue());
- endqstrip();
-
- // on right side of road
- bgnqstrip();
- for (i = _num_markers-1; i > start_marker; i -= step)
- {
- v3f((float *)_right_terrain_data[i].right.getValue());
- v3f((float *)_right_terrain_data[i].left.getValue());
- }
- v3f((float *)_right_terrain_data[start_marker].right.getValue());
- v3f((float *)_right_terrain_data[start_marker].left.getValue());
- endqstrip();
- }
- }
-
-
-
- void Stretch::draw_asphalt(int start_marker, int display_mode) const
- {
- int i;
-
- if (display_mode == RENDER_FILLED)
- {
- Boolean last_backface = getbackface();
-
- if (_type == LOOP)
- {
- setpattern(HOLES);
- backface(FALSE);
- }
-
- cpack(0);
- if ((_type == STRAIGHT) && (_hill_angle == 0.0))
- {
- bgnpolygon();
- v3f((float *)_data[0].left.getValue());
- v3f((float *)_data[0].right.getValue());
- v3f((float *)_data[_num_markers-1].right.getValue());
- v3f((float *)_data[_num_markers-1].left.getValue());
- endpolygon();
- }
- else
- {
- int step = 2*_drawn;
- if (!step) step++;
-
- // draw back to front
- bgnqstrip();
- for (i = _num_markers-1; i > start_marker; i -= step)
- {
- v3f((float *)_data[i].right.getValue());
- v3f((float *)_data[i].left.getValue());
- }
- v3f((float *)_data[start_marker].right.getValue());
- v3f((float *)_data[start_marker].left.getValue());
- endqstrip();
- }
-
- if (_type == LOOP)
- {
- setpattern(0);
- backface(last_backface);
- }
- }
- else // draw in wireframe
- {
- SbVec3f last_left, last_right;
-
- cpack(0xE0E0E0); // XXX
-
- bgnline();
- v3f((float *)_data[start_marker].left.getValue());
- v3f((float *)_data[start_marker].right.getValue());
- endline();
-
- last_left = _data[start_marker].left;
- last_right = _data[start_marker].right;
-
- for (i = start_marker + 1; i < _num_markers; i++)
- {
- bgnline();
- v3f((float *)_data[i].left.getValue());
- v3f((float *)_data[i].right.getValue());
- endline();
-
- bgnline();
- v3f((float *)last_left.getValue());
- v3f((float *)_data[i].left.getValue());
- endline();
-
- bgnline();
- v3f((float *)last_right.getValue());
- v3f((float *)_data[i].right.getValue());
- endline();
-
- last_left = _data[i].left;
- last_right = _data[i].right;
- }
- }
- }
-
-
-
-
- void Stretch::draw_stripes(int start_marker, int display_mode) const
- {
- int i;
-
- // always draw stripes starting on an even marker
- if (start_marker%2)
- start_marker++;
-
- cpack(YELLOW_ASPHALT_COL);
- for (i = start_marker; i < _num_markers - 2; i+=2)
- {
- if (display_mode == RENDER_FILLED)
- {
- bgnpolygon();
- v3f((float *)_median_data[i].left.getValue());
- v3f((float *)_median_data[i].right.getValue());
- v3f((float *)_median_data[i+1].right.getValue());
- v3f((float *)_median_data[i+1].left.getValue());
- endpolygon();
- }
- else
- {
- bgnclosedline();
- v3f((float *)_median_data[i].left.getValue());
- v3f((float *)_median_data[i].right.getValue());
- v3f((float *)_median_data[i+1].right.getValue());
- v3f((float *)_median_data[i+1].left.getValue());
- endclosedline();
- }
- }
- }
-
-
- void Stretch::draw_cars(Car * ignore_car, int mode) const
- {
- for (int i = 0; i < _car_list->length(); i++)
- {
- Car * car = (Car *)(* _car_list)[i];
-
- if (car != ignore_car)
- {
- pushmatrix();
-
- const SbVec3f car_pos = car->get_dynamics()->get_car_position();
- translate(car_pos[0], car_pos[1], car_pos[2]);
-
- SbVec3f axis;
- float angle;
-
- // turn the quaternion into a rotation matrix
- car->get_dynamics()->get_view_orientation().getValue(axis, angle);
-
- // Note negative angle! Looking at car, not from car
- // XXX (at least I think that's why it has to be negative !)
- SbRotation quat(axis, -angle);
- SbMatrix orientation;
- orientation.setRotate(quat);
- multmatrix((Matrix) &orientation[0][0]);
-
- car->draw(mode);
-
- popmatrix();
- }
- }
- }
-
-
-
- // For the given marker, returns the
- // next stretch and the next marker.
- //
- // The next marker will never be the last marker on
- // stretch. Instead it will be the zeroth marker on
- // the next stretch.
- const Stretch * Stretch::get_next_stretch(
- int marker, int &next_marker) const
- {
- Stretch *result;
-
- if (marker == (_num_markers - 2))
- {
- if (_next)
- {
- result = _next;
- next_marker = 0;
- }
- else
- {
- fprintf(stderr,"Reached end of road\n");
- exit(-1);
- }
- }
- else
- {
- result = (Stretch *) this;
- next_marker = marker + 1;
- }
-
- return result;
- }
-
-
- // For the given marker, returns the
- // next stretch and the next marker.
- //
- // The next marker will never be the last marker on
- // stretch. Instead it will be the zeroth marker on
- // the next stretch.
- const Stretch * Stretch::get_prev_stretch(
- int marker, int &prev_marker) const
- {
- Stretch *result;
-
- if (marker == 0)
- {
- if (_prev)
- {
- result = _prev;
- prev_marker = _prev->get_count() - 2;
- }
- else
- {
- fprintf(stderr,"Reached beginning of road\n");
- exit(-1);
- }
- }
- else
- {
- result = (Stretch *) this;
- prev_marker = marker - 1;
- }
-
- return result;
- }
-
-
- // For this stretch, returns a (not necessarily unit) vector specifying
- // the forward road direction from the given marker to the next marker down
- // the SIDE side of the road. SIDE = LEFT, MIDDLE or RIGHT
- const SbVec3f Stretch::get_direction(int marker, int side) const
- {
- SbVec3f d1, d2;
-
- int next_marker;
- const Stretch *next_stretch =
- this->get_next_stretch(marker, next_marker);
-
- switch (side)
- {
- case LEFT:
- d1 = _data[marker].left;
- d2 = next_stretch->_data[next_marker].left;
- break;
-
- case MIDDLE:
- d1 = _data[marker].middle;
- d2 = next_stretch->_data[next_marker].middle;
- break;
-
- case RIGHT:
- d1 = _data[marker].right;
- d2 = next_stretch->_data[next_marker].right;
- break;
- }
-
- return (d2 - d1);
- }
-
-
- // returns a (not necessarily unit) vector specifying the side
- // road direction at the given marker from right to left (side == RIGHT)
- // or left to right (side == LEFT)
- const SbVec3f Stretch::get_side_direction(int marker, int side) const
- {
- SbVec3f l = _data[marker].left;
- SbVec3f r = _data[marker].right;
-
- if (side == RIGHT)
- return (l - r);
- else
- return (r - l);
- }
-
- // this can be overridden by subclasses (like the Curve class)
- // this method really only works for straights and straight hills
- //
- // Returns TRUE if position is on next marker, false if on this marker
- Boolean Stretch::get_marker_offset(
- int marker, // current marker
- const SbVec3f position, // current position
- float *new_offset) // new offset return, 0.0 - 1.0
- {
-
- //printf(" marker %d\n",marker);
- //printf(" position "); print_vec(position);
- SbVec3f forward_vec = this->get_direction(marker,MIDDLE);
- float forward_length = forward_vec.length();
- //printf(" forward length %f, vec "); print_vec(forward_vec);
- SbVec3f car_vec = position - _data[marker].middle;
- //printf(" car vec "); print_vec(car_vec);
- float angle = angle_between(forward_vec, car_vec);
- //printf(" angle %f\n",angle);
-
- SbVec3f proj_vec = project(car_vec, forward_vec);
- float proj_length = proj_vec.length();
- //printf(" proj_length %f, vec ", proj_length); print_vec(proj_vec);
-
- if (proj_length >= forward_length)
- {
- // must have gone on to next segment or we're going backward's!
- *new_offset = (proj_length - forward_length)/forward_length;
-
- //printf(" Returning TRUE\n");
-
- // don't go on to next segment if pointing backwards
- if (angle <= M_PI/2.0)
- return TRUE;
- else
- {
- printf("Wrong Way!\n");
- return FALSE;
- }
- }
- else
- {
- *new_offset = proj_length/forward_length;
-
- //printf(" Returning FALSE\n");
-
- return FALSE;
- }
- }
-
-
- // Returns the middle of the LEFT or RIGHT side of the
- // road at the given marker
- SbVec3f Stretch::road_pos(int side, int marker) const
- {
- if (side == RIGHT)
- return .25*this->get_left(marker) + .75*this->get_right(marker);
- else if (side == LEFT)
- return .75*this->get_left(marker) + .25*this->get_right(marker);
- else
- {
- fprintf(stderr, "Stretch::road_pos illegal side %d\n",side);
- exit(-1);
- }
- }
-
-